package hasthi.tools.analyze;

import static hasthi.common.constants.HasthiConstants.LOGGER_NAME;
import hasthi.common.BaseContext;
import hasthi.common.HasthiException;
import hasthi.common.HasthiOptions;
import hasthi.common.Utils;
import hasthi.common.constants.WSDMConstants;
import hasthi.manager.ManagementLogMessageDocument;
import hasthi.manager.ManagementLogMessageDocument.ManagementLogMessage;
import hasthi.manager.gui.ActionPanel;
import hasthi.manager.gui.UIContext;
import hasthi.manager.monitering.EventListener;
import hasthi.manager.monitering.MoniteringAgent;
import hasthi.metamodel.ExternalResourceModel;
import hasthi.metamodel.resource.ManagedResource;
import hasthi.tools.FailureDetectionTools;

import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlObject;

public class SystemTestDriver2 implements EventListener{
    private static Log log = LogFactory.getLog(LOGGER_NAME);
    private static final int READING_COUNT = 100;
    private ExternalResourceModel externalResourceModel;
    private UIContext context = null;
    private SystemEventsParser parser = new SystemEventsParser();
    private FileWriter out;
    
    private int eventCount = 0; 
    private int readingCount = 0; 
    
    private String[] hosts = new String[]{"silktree.cs.indiana.edu","tyr16.cs.indiana.edu"};
    
    private static ExecutorService executorService = Executors.newFixedThreadPool(2);
    
    public SystemTestDriver2(String propertiesFile) throws HasthiException{
        try {
            Properties properties = new Properties();
            FileInputStream in = new FileInputStream(propertiesFile);
            properties.load(in);
            in.close();
            properties.setProperty(HasthiOptions.BOOTSTRAP_NODE, "tyr12.cs.indiana.edu");
            
            BaseContext baseConfigContext = new BaseContext(properties);
            MoniteringAgent moniteringAgent = new MoniteringAgent(baseConfigContext.getMessageBrokerUrl(),baseConfigContext.getManagementTopic());
            moniteringAgent.addTrigger(this);
            moniteringAgent.startMonitering();
            
            out = new FileWriter("hasthi_event"+System.currentTimeMillis()+".log",true);
            
            

            context = new UIContext(true,baseConfigContext);
            //context.se
            externalResourceModel = context.getExternalResourceModel();
    
        } catch (IOException e) {
            throw new HasthiException(e,HasthiException.FaultCode.LocalError);
        }
    }
    
    public void startTest() throws HasthiException{
        pickAndKillAHost(readingCount%2);    
    }

    public void write(String str){
        try {
            out.write(str);
            out.write("\n");
            out.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    public String getSearchPath() {
        // TODO Auto-generated method stub
        return null;
    }

    public void performTriggerAction(XmlObject event, XmlObject[] matchingResults)
            throws HasthiException {
      //System.out.println("Event recived "+ event);
        eventCount++;
        try {
            if(event instanceof ManagementLogMessageDocument){
                ManagementLogMessageDocument document = (ManagementLogMessageDocument)event;
                ManagementLogMessage logMessage = document.getManagementLogMessage();
                write(logMessage.getMesssage());
                System.out.println(logMessage.getMesssage());
                if(SystemEventsParser.hasMatch(logMessage.getMesssage(), SystemEventsParser.systemRecoveredPattern) != null){
                    externalResourceModel.reload();
                    readingCount++;
                    if(readingCount > READING_COUNT){
                        parser.printSummery();
                        try{out.close();}catch(Exception e){}
                        System.out.println("Test Completed");
                        System.exit(0);
                    }
                    pickAndKillAHost(readingCount%2);
                }
                parser.addEvent(logMessage.getMesssage());
            }
            
            if(eventCount%200 == 0){
                parser.printSummery();
            }
        } catch (InterruptedException e) {
            throw new HasthiException(e,HasthiException.FaultCode.LocalError);
        }
    }
    
    private boolean isActiveResource(ManagedResource resource) throws HasthiException{
        return resource != null && (resource.getState().equals(WSDMConstants.SystemState.BusyState.toString())
                || resource.getState().equals(WSDMConstants.SystemState.SaturatedState.toString())
                ||resource.getState().equals(WSDMConstants.SystemState.IdleState.toString()));
    }
    public  List<QName> waitAndFindResourcesToKIlled(String host2kill,String newHost) throws HasthiException{
        try {
            Thread.sleep(180000);
            if(!FailureDetectionTools.isSocketUp("https://"+newHost+":5003")){
                runCommand("/u/hperera/bin/killhost.sh drlead@"+newHost,true);
                runCommand("/u/hperera/bin/starthost.sh drlead@"+newHost,false);
                Thread.sleep(60000);
                if(!FailureDetectionTools.isSocketUp("https://"+newHost+":5003")){
                    throw new HasthiException("Host "+ newHost + " startup failed",HasthiException.FaultCode.LocalError);
                }
            }
            int retry = 0;
            
            List<QName> resources2Kill = new ArrayList<QName>();
            while(retry < 5){
                ManagedResource[] allResources = externalResourceModel.getAllResources();
                if(isActiveResource(externalResourceModel.getResource(new QName(newHost))) &&
                        isActiveResource(externalResourceModel.getResource(new QName(host2kill)))){
                    resources2Kill.add(new QName(host2kill));
                }
                for(ManagedResource resource:allResources ){
                    if("{http://www.extreme.indiana.edu/lead}FactoryService".equals(resource.getType()) 
                            || "{http://extreme.indiana.edu/xregistry2/2007_02_21}IXregistry".equals(resource.getType())){
                        if(isActiveResource(resource)){
                            resources2Kill.add(resource.getQName());
                        }
                    }
                }
                
                if(resources2Kill.size() >= 3){
                    return resources2Kill;
                }else{
                    System.out.println("Retrying looking for resources to kill, found only "+ resources2Kill);
                    retry++;
                    Thread.sleep(60000);
                }
            }
            throw new HasthiException("System is in Faulty State, only found "+resources2Kill ,HasthiException.FaultCode.LocalError);
        } catch (InterruptedException e) {
            throw new HasthiException(e,HasthiException.FaultCode.LocalError);
        }
    }
    
    private void pickAndKillAHost(final int hostindex) throws HasthiException{
        Thread t = new Thread(new Runnable() {
            public void run() {
                try {
                    String host2kill = hosts[hostindex];
                    String newHost = hosts[(hostindex+1)%2];
                    System.out.println("############## Starting round "+readingCount + " stopping host " 
                            +hosts[hostindex]+"########################");
                    String stdout;
                    if(readingCount > 0){
                        stdout = runCommand("/u/hperera/bin/starthost.sh drlead@"+newHost,false);
                        System.out.println(stdout);
                    }
                    
                    List<QName> resourcesToKIlled = waitAndFindResourcesToKIlled(host2kill, newHost);
                    for(QName name:resourcesToKIlled){
                        context.getBaseContext().getDlogger().info("Resource "+ name + " Stopped");    
                    }
                    context.getBaseContext().getDlogger().info("System Error Occured(Real time)");
                    //We are ready kill the resources
                    stdout = runCommand("/u/hperera/bin/killhost.sh drlead@"+host2kill,true);
                    System.out.println(stdout);
                } catch (HasthiException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        t.start();
        
    }
    public static String runCommand(final String command,final boolean waitfor) throws HasthiException{
        try{
            System.out.println("Command "+command + " submitted");
            if(waitfor){
                Process proces = Runtime.getRuntime().exec(command);
                String stdout = Utils.readFromStream(proces.getInputStream());
                System.out.println("Command "+command + " completed");
                return  stdout;    
            }else{
                Process proces = Runtime.getRuntime().exec(command);
//                final StringBuffer buf = new StringBuffer();
//                Future<?> future = executorService.submit(new Runnable() {
//                    public void run() {
//                        try {
//                            Process proces = Runtime.getRuntime().exec(command);
//                            if(waitfor){
//                                buf.append(Utils.readFromStream(proces.getInputStream()));    
//                            }
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                    }
//                });
                Thread.sleep(10000);
//                if(!future.isDone()){
//                    future.cancel(true);
//                    System.out.println(future.isDone());
//                }
                System.out.println("Command "+command + " completed");
                return "";
            }
        } catch (InterruptedException e) {
            throw new HasthiException(e,HasthiException.FaultCode.LocalError);
        } catch (IOException e) {
            throw new HasthiException(e,HasthiException.FaultCode.LocalError);
        }
    }
    
    public void startStopHosts(){
        
    }
    
    
    public static void main(String[] args) throws HasthiException {
            SystemTestDriver2 systemTestDriver = new SystemTestDriver2(args[0]);
            systemTestDriver.startTest();
            
//            List<QName> resourcesToKIlled = systemTestDriver.waitAndFindResourcesToKIlled("tyr16.cs.indiana.edu","silktree.cs.indiana.edu");
//            System.out.println(resourcesToKIlled);
//        String stdout = runCommand("/u/hperera/bin/killhost.sh drlead@silktree",true);
//        System.out.println(stdout);
//        stdout = runCommand("/u/hperera/bin/starthost.sh drlead@silktree",false);
//        System.out.println(stdout);
//        if(!FailureDetectionTools.isSocketUp("http://silktree:5003")){
//            throw new HasthiException("Host tyr16 startup failed",HasthiException.FaultCode.LocalError); 
//        }
        
    }
    
}
